package com.segersten.othello.service.akka.lobby.dao;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.logging.Logger;

import com.beust.jcommander.internal.Lists;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Maps;
import com.segersten.othello.model.Color;
import com.segersten.othello.service.akka.lobby.BoardReference;
import com.segersten.othello.service.akka.lobby.DomainPlayer;
import com.segersten.othello.service.akka.lobby.Game;

public class InMemoryOngoingGamesDao implements OngoingGamesDao
{
    private Map<DomainPlayer, Set<Game>> ongoingGames = Maps.newHashMap();
    private Map<BoardReference, List<DomainPlayer>> boardReferenceToPlayersMap = Maps.newHashMap();
    private static Logger logger = Logger.getLogger(InMemoryOngoingGamesDao.class.getSimpleName());

    @Override
    public List<Game> getOngoingGames(DomainPlayer domainPlayer)
    {
        return ongoingGames.containsKey(domainPlayer) ? Lists.newArrayList(ongoingGames.get(domainPlayer))
                : new ArrayList<Game>();
    }

    @Override
    public void addGame(BoardReference boardReference, DomainPlayer blackPlayer, DomainPlayer whitePlayer)
    {
        Map<Color, DomainPlayer> players = ImmutableMap.of(Color.BLACK, blackPlayer, Color.WHITE, whitePlayer);
        addGame(blackPlayer, boardReference, players);
        addGame(whitePlayer, boardReference, players);

        boardReferenceToPlayersMap.put(boardReference, Arrays.asList(blackPlayer, whitePlayer));

        logger.fine("Added " + boardReference + "->[" + Arrays.asList(blackPlayer, whitePlayer) + "] to "
                + boardReferenceToPlayersMap);
        // logger.severe("Added " + boardReference + "->[" +
        // Arrays.asList(black, white) + "] to " + boardReferenceToPlayersMap);
    }

    @Override
    public void removeGame(BoardReference boardReference)
    {
        List<DomainPlayer> players = boardReferenceToPlayersMap.remove(boardReference);
        logger.fine("Removed " + boardReference + "->[" + players + "] from " + boardReferenceToPlayersMap);
        // logger.severe("Removed " + boardReference + "->[" + players +
        // "] from " + boardReferenceToPlayersMap);
        for (DomainPlayer p : players) {
            Set<Game> games = this.ongoingGames.get(p);
            Game toRemove = null;
            for (Game game : games) {
                if (game.getBoardReference().equals(boardReference)) {
                    toRemove = game;
                    break;
                }
            }
            games.remove(toRemove);
        }
    }

    // ///////// Private //////////////

    private void addGame(DomainPlayer player, BoardReference boardReference, Map<Color, DomainPlayer> players)
    {
        if (ongoingGames.containsKey(player) == false) {
            ongoingGames.put(player, new HashSet<Game>());
        }
        ongoingGames.get(player).add(new Game(boardReference, players));
    }

}
